/**
 * Copyright (c) [2025] [何屹林]
 *
 * 保留所有权利。
 *
 * 文件名称：first_follow_show.cpp
 * 模块功能说明：
 * 该模块实现逻辑处理类中关于first集合和follow集合相关内容的运算与实现
 *
 * 华南师范大学-计算机学院-网络工程-1班
 * 作者：何屹林-20222132023
 * 完成日期：2025年7月24日
 */
#include "logic.h"


QSet<QString> Logic::get_first(QString s)
{
    if(first_set.contains(s)) return first_set[s];  //如果first集合中包含有非终结符s，直接拿过来用
    else if(!nonFinalizers.contains(s)) return QSet<QString>({s});  //如果s是终结符，直接返回
    else{
        for(auto g:grammars[s])
        {
            int k=0;    //s有多条语法，每一条都需要考虑first元素
            while(k<g.size())
            {
                first_set[g[k]]=get_first(g[k]);
                bool flag=0;
                if (first_set[g[k]].contains("@")) flag = true;     //语句中开头有空白符，不跳出，因为若此处选空白符，first元素应为g[k+1]的first元素
                first_set[s].unite(first_set[g[k]].subtract(QSet<QString>({"@"})));     //空白符暂时去掉
                if (flag) first_set[g[k]].insert("@");              //将空白符加入其中
                else break;
                k++;
            }
            if(k==g.size())
                first_set[s].insert("@");            //每一句都有空白符，退出自然要补空白符
        }
        return first_set[s];
    }
}

void Logic::get_follow()
{
    //基于first集合求follow元素
    bool flag_follow=true;                      //循环结束标志
    follow_set[start_sign].insert("$");         //结束字符
    while(flag_follow)
    {
        flag_follow=false;
        for(auto key:grammars.keys())           //key表示左边的非终结符
        {
            for(auto g:grammars[key])           //g表示key右边的语法
            {
                for(int i=0;i<g.size();i++)     //i表示现在分析的词
                {
                    if(!nonFinalizers.contains(g[i])) continue;//当前分析的词为终结符
                    int j=i+1;                  //当前词的下一个
                    QSet<QString> temp_set;     //暂存g[j]的first集合
                    while(j<g.size())
                    {
                        bool flag=false;
                        if(first_set[g[j]].contains("@")) flag=true;
                        temp_set.unite(first_set[g[j]].subtract(QSet<QString>({"@"})));
                        if(flag) first_set[g[j]].insert("@");
                        else break;
                        j++;
                    }
                    if(j==g.size()) temp_set.insert("@");   //如果j到最后依然有@或者i为g的最后一个词
                    //                    follow_set[g[i]]=temp_set;        不能直接赋值，follow元素不能是@
                    bool mark = false;
                    if (temp_set.contains("@")) mark = true;//如果始终有@，继续分析
                    if(!follow_set[g[i]].contains(temp_set.subtract(QSet<QString>({"@"}))))
                    {
                        for(auto t:temp_set)
                            follow_set[g[i]].insert(t);
                        flag_follow =true;
                    }
                    if (mark && !follow_set[g[i]].contains(follow_set[key])) {
                        for (auto tmp: follow_set[key]) {
                            follow_set[g[i]].insert(tmp);
                        }
                        flag_follow = true;
                    }
                }
            }
        }
    }
    return;
}

void Logic::firstFollowShow(const QString &title,const QStringList& header)
{
    QStringList colHeader=grammars.keys();

    int row=colHeader.size();
    int col=header.size();

    QVector<QVector<QString>> contentTable(row,QVector<QString>(col));
    for(int i=0;i<grammars.size();i++)
    {
        QString first="{",follow="{";
        for(auto s:first_set[grammars.keys()[i]])
            first+=s+" ";
        for(auto s:follow_set[grammars.keys()[i]])
            follow+=s+" ";
        first+="}",follow+="}";

        contentTable[i][0]=first;
        contentTable[i][1]=follow;
    }

    formShow(title,header,colHeader,contentTable);
    return;
}
